package com.apobates.jforum.grief.schema2doc.core.strategy;

import com.apobates.jforum.grief.schema2doc.core.SchemaTableStrategy;
import com.apobates.jforum.grief.schema2doc.core.schema.SchemaDialect;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 基于表名匹配模式
 * 适用于导出少量的表
 */
public class SchemaTableContainsStrategy implements SchemaTableStrategy {
    private final String[] allowTables;
    /**
     * 初始化
     * 适用于导出少量的表。过多会导致SQL长度超出限制
     * @param allowTables 导出的表名称数组
     */
    private SchemaTableContainsStrategy(String[] allowTables) {
        this.allowTables = allowTables;
    }

    /**
     * 初始化
     * 适用于导出少量的表。过多会导致SQL长度超出限制
     * @param prefix 导出表的前缀. 要求格式符合: {prefix}_?
     * @param tables 去掉前缀和下划线后的表名, 例: {prefix}_? 中的: ?
     */
    public static SchemaTableContainsStrategy contact(String prefix, String... tables){
        return new SchemaTableContainsStrategy(
                Stream.of(tables).map(ele->prefix.concat("_").concat(ele)).toArray(String[]::new));
    }

    /**
     *
     * @param tables
     * @return
     */
    public static SchemaTableContainsStrategy of(String... tables){
        return new SchemaTableContainsStrategy(tables);
    }

    @Override
    public Optional<String> sql(SchemaDialect dialect) {
        if(dialect == SchemaDialect.MySQL || dialect == SchemaDialect.MariaDB){
            // FIND_IN_SET("q", "s,q,l") | FIND_IN_SET(pattern, strlist)
            return Optional.of(String.format("FIND_IN_SET(%s, '%s')", placeholder, String.join(",", allowTables)));
        }
        if(dialect == SchemaDialect.PostgreSQL){
            // https://www.postgresql.org/docs/10/functions-comparisons.html#FUNCTIONS-COMPARISONS-IN-SCALAR
            // relname in ('sys_job', 'gen_table')
            return Optional.of(String.format("%s IN(%s)", placeholder, wrapSingleQuotes(allowTables)));
        }
        if(dialect == SchemaDialect.SQLServer){
            // https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2005/ms177682(v=sql.90)?redirectedfrom=MSDN
            //  e.Title IN ('Design Engineer', 'Tool Designer', 'Marketing Assistant');
            return Optional.of(String.format("%s IN(%s)", placeholder, wrapSingleQuotes(allowTables)));
        }
        if(dialect == SchemaDialect.Oracle){
            return Optional.of(String.format("%s IN(%s)", placeholder, wrapSingleQuotes(allowTables)));
        }
        if(dialect == SchemaDialect.SQLite){
            // https://www.sqlitetutorial.net/sqlite-in/
            // name in('msg_motd', 'sys_items')
            return Optional.of(String.format("%s IN(%s)", placeholder, wrapSingleQuotes(allowTables)));
        }
        if (dialect == SchemaDialect.Informix){
            // https://www.ibm.com/docs/en/informix-servers/14.10?topic=condition-use-where-clause-find-subset-values
            // and tabname in('qblob_triggers', 'qjob_details')
            return Optional.of(String.format("%s IN(%s)", placeholder, wrapSingleQuotes(allowTables)));
        }
        return Optional.empty();
    }

    @Override
    public Predicate<String> filter() {
        return passFilter();
    }

    private String wrapSingleQuotes(String[] tables){
        return Stream.of(tables).map(ele->"'"+ele+"'").collect(Collectors.joining(","));
    }

}
